package com.cloud.common.filter;

import cn.hutool.json.JSONUtil;
import com.cloud.common.constants.GlobalConstants;
import com.cloud.common.domain.Result;
import com.cloud.exception.LoginException;
import com.cloud.utils.JWTUtils;
import com.cloud.utils.ToolUtils;
import io.jsonwebtoken.Claims;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;

/**
 * 网关全局过滤器
 * 配置参考: https://doc.xiaominfo.com/docs/middleware-sources/spring-cloud-gateway/spring-gateway-introduction
 *
 * @author yzj
 */

@Component
public class GlobalGateWayFilter implements GlobalFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange webExchange, GatewayFilterChain chain) {
        ServerHttpRequest request = webExchange.getRequest();
        ServerHttpRequest.Builder mutate = request.mutate();
        String requestUrl = request.getURI().getPath();
        // TODO 根据配置跳过不需要认证的Url
        if (GlobalBlankCheck.askUrlAuth(requestUrl)) {
            return chain.filter(webExchange);
        }
        String tokenCode = request.getHeaders().getFirst(GlobalConstants.appTokenHeader);
        String loginToken = request.getHeaders().getFirst(GlobalConstants.tokenHeader);
        if (StringUtils.isEmpty(tokenCode) || StringUtils.isEmpty(loginToken)) {
            return webExchangeMessage(webExchange, LoginException.TOKEN_IS_EMPTY.getCode(),
                    LoginException.TOKEN_IS_EMPTY.getMsg());
        }
        try {
            Claims claims = JWTUtils.parseToken(loginToken);
            if (ObjectUtils.isEmpty(claims)) {
                return webExchangeMessage(webExchange, LoginException.TOKEN_PARSE_ERROR.getCode(),
                        LoginException.TOKEN_PARSE_ERROR.getMsg());
            }
            String userId = JWTUtils.getClaimsKey(claims, GlobalConstants.userId);
            String userName = JWTUtils.getClaimsKey(claims, GlobalConstants.userName);
            String tokenKey = JWTUtils.getClaimsKey(claims, GlobalConstants.tokenKey);
            if (StringUtils.isEmpty(userId) || StringUtils.isEmpty(userName) || StringUtils.isEmpty(tokenKey)) {
                return webExchangeMessage(webExchange, LoginException.INVALID_VERIFY_FAIL.getCode(),
                        LoginException.INVALID_VERIFY_FAIL.getMsg());
            }
            String deptId = JWTUtils.getClaimsKey(claims, GlobalConstants.deptId);
            // 设置用户信息到请求
            addHeader(mutate, GlobalConstants.userId, userId);
            addHeader(mutate, GlobalConstants.userName, userName);
            addHeader(mutate, GlobalConstants.deptId, deptId);
            addHeader(mutate, GlobalConstants.tokenKey, tokenKey);
        } catch (Exception e) {
            return webExchangeMessage(webExchange, LoginException.TOKEN_PARSE_ERROR.getCode(),
                    LoginException.TOKEN_PARSE_ERROR.getMsg());
        }
        return chain.filter(webExchange.mutate().request(mutate.build()).build());
    }

    // 设置ServerHttp 请求头
    private void addHeader(ServerHttpRequest.Builder mutate, String name, Object value) {
        mutate.header(name, ToolUtils.httpEncode(String.valueOf(value)));
    }

    // ServerWebExchange 拦截消息输出
    private Mono<Void> webExchangeMessage(ServerWebExchange webExchange, Integer code, String message) {
        // 这里需要指定响应头部信息,否则会中文乱码
        webExchange.getResponse().getHeaders().add("Content-Type", "application/json;charset=utf-8");
        webExchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
        DataBuffer buffer = webExchange.getResponse().bufferFactory()
                .wrap(JSONUtil.toJsonStr(Result.message(code, message)).getBytes(StandardCharsets.UTF_8));
        return webExchange.getResponse().writeWith(Flux.just(buffer));
    }

    @Override
    public int getOrder() {
        return OrderFilter.GATE_WAY_GLOBAL_FILTER;
    }

}
